<template>
	<view v-if="visible" class="image-preview-container">
		<!-- 全屏遮罩 -->
		<view class="preview-mask">
			<!-- 图片预览区域 -->
			<view class="preview-content" ref="previewContent">
				<!-- 可拖动缩放的图片容器 -->
				<view 
					class="image-container"
					@touchstart="onTouchStart"
					@touchmove="onTouchMove"
					@touchend="onTouchEnd"
					@touchcancel="onTouchEnd"
				>
					<image 
						:src="imageSrc" 
						mode="widthFix" 
						class="preview-image"
						:style="imageStyle"
						@load="onImageLoad"
						@error="onImageError"
					></image>
				</view>
				
				<!-- 固定的截取框遮罩层 -->
				<view class="crop-overlay">
					<!-- 上遮罩 -->
					<view class="overlay-top"></view>
					
					<!-- 中间行 -->
					<view class="overlay-middle">
						<!-- 左遮罩 -->
						<view class="overlay-left"></view>
						<!-- 截取框 -->
						<view class="crop-frame">
							<view class="crop-corner crop-corner-tl"></view>
							<view class="crop-corner crop-corner-tr"></view>
							<view class="crop-corner crop-corner-bl"></view>
							<view class="crop-corner crop-corner-br"></view>
						</view>
						<!-- 右遮罩 -->
						<view class="overlay-right"></view>
					</view>
					
					<!-- 下遮罩 -->
					<view class="overlay-bottom"></view>
				</view>
				
				<!-- 操作提示 -->
				<view class="operation-tips">
					<text>拖动调整位置，双指缩放调整大小</text>
				</view>
			</view>
				
			<!-- 底部操作栏 -->
			<view class="action-bar">
				<view class="action-btn cancel-btn" @click="cancel">
					<text>取消</text>
				</view>
				
				<view class="action-btn reset-btn" @click="resetTransform">
					<text>重置</text>
				</view>
				
				<view class="action-btn confirm-btn" @click="confirm">
					<text>确认</text>
				</view>
			</view>
		</view>
		
		<!-- 隐藏的canvas用于图片裁剪 -->
		<canvas 
			canvas-id="cropCanvas" 
			:style="{ width: cropSize + 'rpx', height: cropSize + 'rpx', position: 'absolute', left: '-9999px', top: '-9999px' }"
		></canvas>
	</view>
</template>

<script>
	export default {
		name: 'ImagePreview',
		props: {
			visible: {
				type: Boolean,
				default: false
			},
			imageSrc: {
				type: String,
				default: ''
			}
		},
		data() {
			return {
				// 图片状态
				imageLoaded: false,
				hasError: false,
				
				// 图片尺寸信息
				imageWidth: 0,
				imageHeight: 0,
				containerWidth: 0,
				containerHeight: 0,
				
				// 截取框尺寸（rpx）
				cropSize: 500,
				
				// 变换状态
				scale: 1,
				translateX: 0,
				translateY: 0,
				
				// 触摸状态
				touches: [],
				lastTouch: null,
				startDistance: 0,
				startScale: 1,
				startTranslateX: 0,
				startTranslateY: 0,
				
				// 变换限制
				minScale: 0.5,
				maxScale: 3
			}
		},
		computed: {
			// 图片样式
			imageStyle() {
				return {
					transform: `translate(${this.translateX}px, ${this.translateY}px) scale(${this.scale})`,
					transformOrigin: 'center center',
					transition: this.touches.length > 0 ? 'none' : 'transform 0.2s ease'
				}
			}
		},
		watch: {
			visible(newVal) {
				if (newVal) {
					this.$nextTick(() => {
						setTimeout(() => {
							this.initContainer()
						}, 100)
					})
				}
			}
		},
		methods: {
			// 取消操作
			cancel() {
				this.$emit('cancel')
			},
			
			// 确认操作
			confirm() {
				this.cropImage().then(croppedImageSrc => {
					this.$emit('confirm', croppedImageSrc)
				}).catch(error => {
					console.error('图片裁剪失败:', error)
					this.$emit('confirm', this.imageSrc)
				})
			},
			
			// 重置变换
			resetTransform() {
				this.scale = 1
				this.translateX = 0
				this.translateY = 0
			},
			
			// 初始化容器信息
			initContainer() {
				const query = uni.createSelectorQuery().in(this)
				query.select('.preview-content').boundingClientRect(data => {
					if (data) {
						this.containerWidth = data.width
						this.containerHeight = data.height
						console.log('容器尺寸:', data.width, data.height)
					}
				}).exec()
			},
			
			// 触摸开始
			onTouchStart(event) {
				event.preventDefault()
				this.touches = Array.from(event.touches)
				this.lastTouch = this.touches[0]
				
				if (this.touches.length === 1) {
					// 单指拖动
					this.startTranslateX = this.translateX
					this.startTranslateY = this.translateY
					console.log('单指触摸开始')
				} else if (this.touches.length === 2) {
					// 双指缩放
					this.startScale = this.scale
					this.startDistance = this.getDistance(this.touches[0], this.touches[1])
					this.startTranslateX = this.translateX
					this.startTranslateY = this.translateY
					console.log('双指触摸开始，距离:', this.startDistance)
				}
			},
			
			// 触摸移动
			onTouchMove(event) {
				event.preventDefault()
				const touches = Array.from(event.touches)
				
				if (touches.length === 1) {
					// 单指拖动
					this.handleDrag(touches[0])
				} else if (touches.length === 2) {
					// 双指缩放
					this.handlePinch(touches)
				}
			},
			
			// 触摸结束
			onTouchEnd(event) {
				this.touches = []
				this.lastTouch = null
				this.startDistance = 0
				console.log('触摸结束')
			},
			
			// 处理拖动
			handleDrag(touch) {
				if (!this.lastTouch) return
				
				const deltaX = touch.clientX - this.lastTouch.clientX
				const deltaY = touch.clientY - this.lastTouch.clientY
				
				let newTranslateX = this.startTranslateX + deltaX
				let newTranslateY = this.startTranslateY + deltaY
				
				// 应用边界限制
				const limits = this.getMoveLimits()
				newTranslateX = Math.max(limits.minX, Math.min(limits.maxX, newTranslateX))
				newTranslateY = Math.max(limits.minY, Math.min(limits.maxY, newTranslateY))
				
				this.translateX = newTranslateX
				this.translateY = newTranslateY
				
				console.log('拖动:', { deltaX, deltaY, translateX: this.translateX, translateY: this.translateY })
			},
			
			// 处理缩放
			handlePinch(touches) {
				if (touches.length !== 2) return
				
				const currentDistance = this.getDistance(touches[0], touches[1])
				if (this.startDistance === 0) {
					this.startDistance = currentDistance
					return
				}
				
				const scaleRatio = currentDistance / this.startDistance
				let newScale = this.startScale * scaleRatio
				newScale = Math.max(this.minScale, Math.min(this.maxScale, newScale))
				
				// 计算缩放中心点
				const centerX = (touches[0].clientX + touches[1].clientX) / 2
				const centerY = (touches[0].clientY + touches[1].clientY) / 2
				
				// 计算相对于容器中心的偏移
				const containerCenterX = this.containerWidth / 2
				const containerCenterY = this.containerHeight / 2
				const offsetX = centerX - containerCenterX
				const offsetY = centerY - containerCenterY
				
				// 计算缩放后的位置调整
				const scaleChange = newScale - this.startScale
				let newTranslateX = this.startTranslateX - offsetX * scaleChange
				let newTranslateY = this.startTranslateY - offsetY * scaleChange
				
				// 应用边界限制
				const limits = this.getMoveLimits(newScale)
				newTranslateX = Math.max(limits.minX, Math.min(limits.maxX, newTranslateX))
				newTranslateY = Math.max(limits.minY, Math.min(limits.maxY, newTranslateY))
				
				this.scale = newScale
				this.translateX = newTranslateX
				this.translateY = newTranslateY
				
				console.log('缩放:', { scale: newScale, translateX: this.translateX, translateY: this.translateY })
			},
			
			// 计算两点间距离
			getDistance(touch1, touch2) {
				const dx = touch1.clientX - touch2.clientX
				const dy = touch1.clientY - touch2.clientY
				return Math.sqrt(dx * dx + dy * dy)
			},
			
			// 获取移动边界限制
			getMoveLimits(scale = this.scale) {
				if (!this.containerWidth || !this.containerHeight) {
					return { minX: -1000, maxX: 1000, minY: -1000, maxY: 1000 }
				}
				
				// 简化的边界计算
				const maxMoveX = this.containerWidth * 1.5
				const maxMoveY = this.containerHeight * 1.5
				
				return {
					minX: -maxMoveX,
					maxX: maxMoveX,
					minY: -maxMoveY,
					maxY: maxMoveY
				}
			},
			
			// 图片加载成功
			onImageLoad(event) {
				console.log('图片加载成功')
				this.imageLoaded = true
				this.hasError = false
				
				const detail = event.detail
				this.imageWidth = detail.width
				this.imageHeight = detail.height
				
				// 延迟获取容器信息
				this.$nextTick(() => {
					setTimeout(() => {
						this.initContainer()
					}, 100)
				})
			},
			
			// 图片加载失败
			onImageError() {
				console.log('图片加载失败')
				this.hasError = true
				this.imageLoaded = false
				uni.showToast({
					title: '图片加载失败',
					icon: 'none'
				})
			},
			
			// 裁剪图片
			cropImage() {
				return new Promise((resolve, reject) => {
					if (!this.imageLoaded || this.hasError) {
						reject('图片未加载或加载失败')
						return
					}
					
					// 计算裁剪参数
					const cropParams = this.calculateCropParams()
					
					// 使用canvas进行图片裁剪
					const ctx = uni.createCanvasContext('cropCanvas', this)
					const canvasSize = uni.upx2px(this.cropSize)
					
					// 清空canvas
					ctx.clearRect(0, 0, canvasSize, canvasSize)
					
					// 绘制裁剪后的图片
					ctx.drawImage(
						this.imageSrc,
						cropParams.sx, cropParams.sy, cropParams.sWidth, cropParams.sHeight,
						0, 0, canvasSize, canvasSize
					)
					
					ctx.draw(false, () => {
						// 导出图片
						uni.canvasToTempFilePath({
							canvasId: 'cropCanvas',
							width: canvasSize,
							height: canvasSize,
							destWidth: canvasSize,
							destHeight: canvasSize,
							fileType: 'jpg',
							quality: 0.8,
							success: (res) => {
								resolve(res.tempFilePath)
							},
							fail: (error) => {
								reject(error)
							}
						}, this)
					})
				})
			},
			
			// 计算裁剪参数
			calculateCropParams() {
				const cropSizePx = uni.upx2px(this.cropSize)
				
				// 计算当前图片的实际显示尺寸
				const currentImageWidth = this.imageWidth * this.scale
				const currentImageHeight = this.imageHeight * this.scale
				
				// 计算图片中心点在显示区域中的位置
				const imageCenterX = this.containerWidth / 2 + this.translateX
				const imageCenterY = this.containerHeight / 2 + this.translateY
				
				// 计算截取框在显示区域中的位置（固定在中央）
				const cropCenterX = this.containerWidth / 2
				const cropCenterY = this.containerHeight / 2
				
				// 计算截取框相对于图片中心的偏移
				const offsetX = cropCenterX - imageCenterX
				const offsetY = cropCenterY - imageCenterY
				
				// 将偏移转换为图片坐标系（考虑缩放）
				const imageOffsetX = offsetX / this.scale
				const imageOffsetY = offsetY / this.scale
				
				// 计算在原始图片上的裁剪区域
				const originalImageCenterX = this.imageWidth / 2
				const originalImageCenterY = this.imageHeight / 2
				
				// 计算裁剪区域在原始图片上的中心点
				const cropCenterInOriginalX = originalImageCenterX + imageOffsetX
				const cropCenterInOriginalY = originalImageCenterY + imageOffsetY
				
				// 计算裁剪区域的尺寸（在原始图片上）
				const cropSizeInOriginal = cropSizePx / this.scale
				
				// 计算最终的裁剪参数
				const sx = Math.max(0, cropCenterInOriginalX - cropSizeInOriginal / 2)
				const sy = Math.max(0, cropCenterInOriginalY - cropSizeInOriginal / 2)
				const sWidth = Math.min(this.imageWidth - sx, cropSizeInOriginal)
				const sHeight = Math.min(this.imageHeight - sy, cropSizeInOriginal)
				
				return { sx, sy, sWidth, sHeight }
			}
		}
	}
</script>

<style lang="scss" scoped>
	.image-preview-container {
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		z-index: 9999;
	}
	
	.preview-mask {
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background-color: rgba(0, 0, 0, 0.9);
		display: flex;
		flex-direction: column;
		touch-action: none;
		overscroll-behavior: contain;
	}
	
	.preview-content {
		flex: 1;
		display: flex;
		align-items: center;
		justify-content: center;
		position: relative;
		overflow: hidden;
	}
	
	.image-container {
		position: relative;
		width: 100%;
		height: 100%;
		display: flex;
		align-items: center;
		justify-content: center;
		touch-action: none;
	}

	.preview-image {
		max-width: 100%;
		max-height: 100%;
		border-radius: 16rpx;
		user-select: none;
		pointer-events: none;
	}
	
	/* 截取框遮罩层 */
	.crop-overlay {
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		display: flex;
		flex-direction: column;
		pointer-events: none;
	}
	
	/* 遮罩区域 - 半透明黑色 */
	.overlay-top,
	.overlay-bottom,
	.overlay-left,
	.overlay-right {
		background-color: rgba(0, 0, 0, 0.6);
	}
	
	.overlay-top,
	.overlay-bottom {
		flex: 1;
	}
	
	.overlay-middle {
		display: flex;
		flex-direction: row;
		height: 500rpx; /* 截取框高度 */
	}
	
	.overlay-left,
	.overlay-right {
		flex: 1;
	}
	
	/* 截取框 */
	.crop-frame {
		width: 500rpx; /* 截取框宽度 */
		height: 500rpx; /* 截取框高度 */
		position: relative;
		border: 2rpx solid #ffffff;
		background-color: transparent;
		box-sizing: border-box;
	}
	
	/* 截取框四个角的装饰 */
	.crop-corner {
		position: absolute;
		width: 50rpx;
		height: 50rpx;
		border: 6rpx solid #ffffff;
		box-shadow: 0 0 8rpx rgba(0, 0, 0, 0.3);
	}
	
	.crop-corner-tl {
		top: -6rpx;
		left: -6rpx;
		border-right: none;
		border-bottom: none;
		border-top-left-radius: 8rpx;
	}
	
	.crop-corner-tr {
		top: -6rpx;
		right: -6rpx;
		border-left: none;
		border-bottom: none;
		border-top-right-radius: 8rpx;
	}
	
	.crop-corner-bl {
		bottom: -6rpx;
		left: -6rpx;
		border-right: none;
		border-top: none;
		border-bottom-left-radius: 8rpx;
	}
	
	.crop-corner-br {
		bottom: -6rpx;
		right: -6rpx;
		border-left: none;
		border-top: none;
		border-bottom-right-radius: 8rpx;
	}
	
	/* 操作提示 */
	.operation-tips {
		position: absolute;
		bottom: 120rpx;
		left: 50%;
		transform: translateX(-50%);
		background-color: rgba(0, 0, 0, 0.7);
		border-radius: 40rpx;
		padding: 16rpx 32rpx;
		
		text {
			color: rgba(255, 255, 255, 0.8);
			font-size: 24rpx;
		}
	}
	
	.action-bar {
		display: flex;
		justify-content: space-around;
		padding: 40rpx 60rpx;
		padding-bottom: calc(40rpx + env(safe-area-inset-bottom));
		background: linear-gradient(180deg, transparent 0%, rgba(0, 0, 0, 0.3) 100%);
	}
	
	.action-btn {
		flex: 1;
		max-width: 280rpx;
		height: 88rpx;
		border-radius: 44rpx;
		display: flex;
		align-items: center;
		justify-content: center;
		margin: 0 20rpx;
		
		text {
			font-size: 32rpx;
			font-weight: 500;
		}
		
		&:active {
			transform: scale(0.98);
			transition: transform 0.1s;
		}
	}
	
	.cancel-btn {
		background-color: rgba(255, 255, 255, 0.2);
		border: 2rpx solid rgba(255, 255, 255, 0.3);
		
		text {
			color: #fff;
		}
		
		&:active {
			background-color: rgba(255, 255, 255, 0.1);
		}
	}
	
	.reset-btn {
		background-color: rgba(255, 255, 255, 0.15);
		border: 2rpx solid rgba(255, 255, 255, 0.25);
		
		text {
			color: #fff;
		}
		
		&:active {
			background-color: rgba(255, 255, 255, 0.1);
		}
	}
	
	.confirm-btn {
		background-color: #007aff;
		
		text {
			color: #fff;
		}
		
		&:active {
			background-color: #0056cc;
		}
	}
</style>